home *** CD-ROM | disk | FTP | other *** search
- .include "global.s"
-
- .area _CODE
-
- ;; 16-bit division
- ;;
- ;; Entry conditions
- ;; BC = dividend
- ;; DE = divisor
- ;;
- ;; Exit conditions
- ;; BC = quotient
- ;; DE = remainder
- ;; If divisor is non-zero, carry=0
- ;; If divisor is 0, carry=1 and both quotient and remainder are 0
- ;;
- ;; Register used: AF,BC,DE,HL
- .div16::
- .mod16::
- ;; Determine sign of quotient by xor-ing high bytes of dividend
- ;; and divisor. Quotient is positive if signs are the same, negative
- ;; if signs are different
- ;; Remainder has same sign as dividend
- LD A,B ; Get high byte of dividend
- LD (.srem),A ; Save as sign of remainder
- XOR D ; Xor with high byte of divisor
- LD (.squot),A ; Save sign of quotient
- ;; Take absolute value of divisor
- BIT 7,D
- JP Z,.chkde ; Jump if divisor is positive
- SUB A ; Substract divisor from 0
- SUB E
- LD E,A
- SBC A ; Propagate borrow (A=0xFF if borrow)
- SUB D
- LD D,A
- ;; Take absolute value of dividend
- .chkde:
- BIT 7,B
- JP Z,.dodiv ; Jump if dividend is positive
- SUB A ; Substract dividend from 0
- SUB C
- LD C,A
- SBC A ; Propagate borrow (A=0xFF if borrow)
- SUB B
- LD B,A
- ;; Divide absolute values
- .dodiv:
- CALL .divu16
- RET C ; Exit if divide by zero
- ;; Negate quotient if it is negative
- LD A,(.squot)
- AND #0x80
- JP Z,.dorem ; Jump if quotient is positive
- SUB A ; Substract quotient from 0
- SUB C
- LD C,A
- SBC A ; Propagate borrow (A=0xFF if borrow)
- SUB B
- LD B,A
- .dorem:
- ;; Negate remainder if it is negative
- LD A,(.srem)
- AND #0x80
- RET Z ; Return if remainder is positive
- SUB A ; Substract remainder from 0
- SUB E
- LD E,A
- SBC A ; Propagate remainder (A=0xFF if borrow)
- SUB D
- LD D,A
- RET
- .divu16::
- .modu16::
- ;; Check for division by zero
- LD A,E
- OR D
- JR NZ,.divide ; Branch if divisor is non-zero
- LD BC,#0x00 ; Divide by zero error
- LD D,B
- LD E,C
- SCF ; Set carry, invalid result
- RET
- .divide:
- LD L,C ; L = low byte of dividend/quotient
- LD H,B ; H = high byte of dividend/quotient
- LD BC,#0x00 ; BC = remainder
- OR A ; Clear carry to start
- LD A,#16 ; 16 bits in dividend
- .dvloop:
- ;; Shift next bit of quotient into bit 0 of dividend
- ;; Shift next MSB of dividend into LSB of remainder
- ;; BC holds both dividend and quotient. While we shift a bit from
- ;; MSB of dividend, we shift next bit of quotient in from carry
- ;; HL holds remainder
- ;; Do a 32-bit left shift, shifting carry to L, L to H,
- ;; H to C, C to B
- LD (.dcnt),A
- RL L ; Carry (next bit of quotient) to bit 0
- RL H ; Shift remaining bytes
- RL C
- RL B ; Clears carry since BC was 0
- ;; If remainder is >= divisor, next bit of quotient is 1. This
- ;; bit goes to carry
- PUSH BC ; Save current remainder
- LD A,C ; Substract divisor from remainder
- SBC E
- LD C,A
- LD A,B
- SBC D
- LD B,A
- CCF ; Complement borrow so 1 indicates a
- ; successful substraction (this is the
- ; next bit of quotient)
- JR C,.drop ; Jump if remainder is >= dividend
- POP BC ; Otherwise, restore remainder
- JR .nodrop
- .drop:
- INC SP
- INC SP
- .nodrop:
- LD A,(.dcnt)
- DEC A ; DEC does not affect carry flag
- JR NZ,.dvloop
- ;; Shift last carry bit into quotient
- LD D,B ; DE = remainder
- LD E,C
- RL L ; Carry to L
- LD C,L ; C = low byte of quotient
- RL H
- LD B,H ; B = high byte of quotient
- OR A ; Clear carry, valid result
- RET
-
- .div8::
- .mod8::
- LD A,C ; Sign extend
- RLCA
- SBC A
- LD B,A
- LD A,E ; Sign extend
- RLCA
- SBC A
- LD D,A
- JP .div16
-
- .divu8::
- .modu8::
- LD B,#0x00
- LD D,#0x00
- JP .divu16
-
- .area _BSS
-
- .srem:
- .ds 0x01 ; Sign of quotient
- .squot:
- .ds 0x01 ; Sign of remainder
- .dcnt:
- .ds 0x01 ; Counter for division
-